﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web;
using com.kmer.ApiServer.Properties;
using com.kmer.Security;
using kmer.Helper;
using kmer.Web.Helper;
using com.kmer.library.com.kmer.Helper;

// ReSharper disable once CheckNamespace
namespace com.kmer.ApiServer {
    /// <summary>
    /// API入口
    /// 检查并分发到到各个Handler
    /// </summary>
    public class APIHandlerFactory : IHttpHandlerFactory {
	    private IHttpHandler _handler;
	    private static bool _scaned;

        /// <summary>
        /// 入口
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requestType"></param>
        /// <param name="url"></param>
        /// <param name="pathTranslated"></param>
        /// <returns></returns>
        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            //APIHandlerFactory.FindAndRegister(false);
            if (context.Request.FilePath.EndsWith("/api.ashx")
                || context.Request.FilePath.EndsWith("/api"))
            {
                var c = context.Request.Get("c", "Default");
                if (c.ToLower() == "html")
                    _handler = new HtmlHanlder();
                else if (c.StartsWith("WX"))
                {
                    _handler = getWXHandler(c + "Handler");
                }
                else
                    _handler = getHandler(c + "Handler");
            }
            else
            {
                url = url.Split('.')[0].Substring(5);
                if (url.ToLower() == "html")
                    _handler = new HtmlHanlder();
                else if (url.StartsWith("WX"))
                {
                    _handler = getWXHandler(url + "Handler");
                }
                else
                    _handler = getHandler(url + "Handler");
            }
            var request = context.Request;
            if (request.HttpMethod.ToUpper() == "OPTIONS")
            {
                return new OptionsHandler();
            }
            return _handler ?? new DefaultHandler();
        }

        /// <summary>
		/// 查找并注册命令
		/// </summary>
		/// <param name="assembly"></param>
		public static void FindAndRegister(string assembly) {
			var ass = Assembly.Load(assembly);
			if (ass != null) {
				FindAndRegister(ass);
			}
		}
		/// <summary>
		/// 查找并注册命令
		/// </summary>
		public static void FindAndRegister(bool onlyScanMe = true) {
			if (_scaned) return;
			_scaned = true;
			if (onlyScanMe) {
				var assembly = Assembly.GetAssembly(typeof(APIHandlerFactory));
				FindAndRegister(assembly);
			} else {
				var assemblys = AppDomain.CurrentDomain.GetAssemblies().Where(item => item.GlobalAssemblyCache == false);
				foreach (var k in assemblys) {
					FindAndRegister(k);
				}
			}
			_scaned = false;
		}
		/// <summary>
		/// 查找并注册命令
		/// </summary>
		/// <param name="assembly"></param>
		public static void FindAndRegister(Assembly assembly) {
			var type = typeof(BaseHandler);
			Type[] types = null;
			try {
				types = assembly.GetTypes();
			} catch (ReflectionTypeLoadException ex) {
				var err = ex.LoaderExceptions.Select(lex => lex.Message).ToArray();
				Log.Error("加载Type（{3}）失败：{0}\n详细信息：{1}\n\n{2}\n", "ReflectionTypeLoadException",
					ex.Message,
					ex.ToString(),
					err.Join(Environment.NewLine),
					assembly.FullName
					);

			} catch (Exception ex) {
				Log.Error("注册Type（{2}）失败：{0}\n详细信息：{1}", "Exception", ex.Message, ex.ToString(),
					assembly.FullName
					);
			}
			if (types == null || types.Length < 1) return;
			try {
				var modules = types.Where(item => item.BaseType == type || item.IsSubclassOf(type)).ToArray();
				if(modules.Any()==false)return; ;
				foreach (var k in modules) {
					Register(k);
				}
			} catch (ReflectionTypeLoadException ex) {
				var err = ex.LoaderExceptions.Select(lex => lex.Message).ToArray();
				Log.Error("加载Type（{3}）失败：{0}\n详细信息：{1}\n\n{2}\n", "ReflectionTypeLoadException",
					ex.Message, 
					ex.ToString(),
                    err.Join(Environment.NewLine),
					assembly.FullName
					);
				
            } catch (Exception ex) {
				Log.Error("注册Type（{2}）失败：{0}\n详细信息：{1}", "Exception", ex.Message, ex.ToString(),
					assembly.FullName
					);
			}
		}

        /// <summary>
        /// getHandler
        /// </summary>
        /// <param name="controller"></param>
        /// <returns></returns>
		public static BaseHandler getHandler(string controller) {
			if (ApiList == null || ApiList.Count == 0) return null;
			var handler = ApiList.Where(item => item.Key == controller).Select(item => item.Value).FirstOrDefault();
			if (handler == null)
				return null;
			return (BaseHandler) Activator.CreateInstance(handler);
			//return handler;
		}

        /// <summary>
        /// getWXHandler
        /// </summary>
        /// <param name="controller"></param>
        /// <returns></returns>
		public static WXBaseHandler getWXHandler(string controller) {
			if (ApiList == null || ApiList.Count == 0) return null;
			var handler = ApiList.Where(item => item.Key == controller).Select(item => item.Value).FirstOrDefault();
			if (handler == null)
				return null;
			return (WXBaseHandler) Activator.CreateInstance(handler);
			//return handler;
		}

	    internal static Dictionary<string, Type> ApiList;
		/// <summary>
		/// 注册APIHandler
		/// </summary>
		/// <param name="pHander"></param>
		public static void Register(Type pHander) {
			var t = pHander;
			while (t != null && t.BaseType != typeof(BaseHandler)) {
				t = t.BaseType;
			}
			if (t == null) return;
			if (ApiList == null) ApiList = new Dictionary<string, Type>();
			if (ApiList.Any(item => item.Key == pHander.Name)) return;
			//var inc = Activator.CreateInstance(pHander) as BaseHandler;
			//Log.WriteLog("注册API Handler：{0}", args: pHander);
			RcHelper.AddController((BaseHandler)Activator.CreateInstance(pHander));
			ApiList.Add(pHander.Name, pHander);
		}
		/// <summary>
		/// 注册APIHandler
		/// </summary>
		/// <param name="pHander"></param>
		public static void WXRegister(Type pHander) {
			var t = pHander;
			while (t != null && t.BaseType != typeof(WXBaseHandler)) {
				t = t.BaseType;
			}
			if (t == null) return;
			if (ApiList == null) ApiList = new Dictionary<string, Type>();
			if (ApiList.Any(item => item.Key == pHander.Name)) return;
			//var inc = Activator.CreateInstance(pHander) as BaseHandler;
			//Log.WriteLog("注册API Handler：{0}", args: pHander);
			//RcHelper.AddController((WXBaseHandler)Activator.CreateInstance(pHander));
			ApiList.Add(pHander.Name, pHander);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="handler"></param>
		public void ReleaseHandler(IHttpHandler handler) {
			_handler = null;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="appId"></param>
		/// <param name="appSecret"></param>
		/// <returns></returns>
		internal static string createAccessToken(Guid appId, string appSecret) {
			return EntryCode.EncodeCode(MD5.GetPassWord($"{appId}{DateTime.Now:yyyyMMddHHmmssyyyyy}{appSecret}"), "com.kmer.ApiServer");
		}
	}
    /// <summary>
    /// 处理html文件
    /// </summary>
    public class HtmlHanlder : IHttpHandler{
		/// <summary>
		/// 
		/// </summary>
        public bool IsReusable => false;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
        public void ProcessRequest(HttpContext context) {
            var path = context.Request.PathInfo;
            if (string.IsNullOrWhiteSpace(path)) {
                //.Aggregate("", (current, s) => current + s);
                var list =
                    APIHandlerFactory.ApiList.Select(i => new {
                        Controller = i.Key.Replace("Handler", ""),
                        Dll = i.Value.Assembly.GetName().Name,
                        Description = GetDescription(i.Value),
                    }).OrderBy(i => i.Dll).ThenBy(i => i.Controller);
                var sp = new StringBuilder();
                var lastDll = "";
                foreach (var item in list) {
                    if (string.IsNullOrWhiteSpace(lastDll)) {
                        lastDll = item.Dll;
                        sp.AppendLine(
                            $"<div class=\"panel-heading\"><div class=\" disabled\">{item.Dll}</div></div><ul class=\"list-group\">");
                        //continue;
                    }
                    if (lastDll != item.Dll) {
                        lastDll = item.Dll;
                        sp.AppendLine(
                            $"</ul><div class=\"panel-heading\"><div class=\" disabled\">{item.Dll}</div></div><ul class=\"list-group\">");
                    }
                    sp.AppendLine(
                        $"<li class=\"list-group-item\"><a href=\"/api/html.ashx/{item.Controller}\" data-dll=\"{item.Dll}\">{item.Controller}</a> {item.Description}</li>");
                }
                sp.AppendLine("</ul>");
                //.Aggregate("",(s, current) => s + $"<li class=\"list-group-item\"><a href=\"/api/html.ashx/{current}\">{current}</a></li>");
                context.Response.Write(Resources.ApiListTpl.Replace("[API-LIST]", sp.ToString()));
            } else {
                if (context.Request.Path.IndexOf("prism.css", StringComparison.Ordinal) >0){
                    context.Response.ContentType = "text/css";
                    context.Response.Write(Resources.prism_css);
                } else if (context.Request.Path.IndexOf("prism.js", StringComparison.Ordinal) > 0){
                    context.Response.ContentType = "application/javascript";
                    context.Response.Write(Resources.prism_js);
                }else{
                    var ps = path.Split('/');
                    context.Response.Write(Resources.ApiTpl.Replace("[CONTROLLER]", ps[1])
                        .Replace("[ACTION]", ps.Length > 2 ? ps[2] : "列表"));
                }
            }
        }

	    internal static string GetDescription(Type type){
            var d = type.GetCustomAttribute<DescriptionAttribute>();
            return d?.Description;
            //var description = (DescriptionAttribute)attribs.FirstOrDefault(item => item is DescriptionAttribute);
        }
    }// end class
}
